// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "MovableActorBase.h"
#include "Components/ActorComponent.h"
#include "MovableInteractionComponent.generated.h"

class AMovableActorBase;

UCLASS( ClassGroup=(Custom), meta=(BlueprintSpawnableComponent) )
class RUNTIMEMOVABLEACTOR_API UMovableInteractionComponent : public UActorComponent
{
	GENERATED_BODY()

public:	
	UMovableInteractionComponent();

protected:
	virtual void BeginPlay() override;

public:	
	virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override;

	/**
	 * 检测 Actor 是否可移动
	 */
	UFUNCTION(BlueprintCallable, Category="Movable Interaction")
	void DetectMovableActor(bool Debug=false);

	/**
	 * 获取当前选中的 可移动 Actor
	 * @return 
	 */
	UFUNCTION(BlueprintPure, Category="Movable Interaction")
	AMovableActorBase* GetCurrentSelectedActor() const {return SelectedMovableActor.Get();};

	/**
	 * 获取当前被选中的 Actor 控制手柄占屏幕空间大小
	 * @return 
	 */
	FVector2D GetHandleSizeOnScreen();

	UFUNCTION(BlueprintPure, Category="Movable Interaction", meta=(DisplayName="Get Handle Size On Screen"))
	FVector2D BP_GetHandleSizeOnScreen();

	/**
	 * 更新当前被选中的 Actor 控制手柄占屏幕空间大小
	 */
	void UpdateHandleSizeOnScreen();

	/**
	 * 检测被悬浮的控制手柄
	 */
	void DetectHoveredHandle();

	/**
	 * 当开始拖拽时
	 */
	UFUNCTION(BlueprintCallable, Category="Movable Interaction")
	void OnDragBegin();

	/**
	 * 当停止拖拽时
	 */
	UFUNCTION(BlueprintCallable, Category="Movable Interaction")
	void OnDragEnd();

	/**
	 * 切换变换模式
	 * @param TransformMode 
	 */
	UFUNCTION(BlueprintCallable, Category="Movable Interaction")
	void ToggleTransformMode(ETransformMode TransformMode);
	/**
	 * 获取鼠标世界位置、方向
	 * @param WorldPos 
	 * @param WorldDirection 
	 */
	bool GetMouseWorldPositionDirection(FVector& WorldPos, FVector& WorldDirection);

	/**
	 * 更新约束平面
	 */
	void UpdateConstraintPlane();

	/**
	 * 获取鼠标在约束平面上的位置
	 * @return 
	 */
	FVector GetMousePosOnConstraintPlane();
	
	void DoTranslate();
	void DoRotate();
	void DoScale();
private:
	TWeakObjectPtr<APawn> Owner;
	TWeakObjectPtr<APlayerController> PlayerPC;
	
	TWeakObjectPtr<AMovableActorBase> SelectedMovableActor;
	TWeakObjectPtr<AMovableActorBase> LastSelectedMovableActor;

	TWeakObjectPtr<UStaticMeshComponent> CurrentHoverCmp;
	TWeakObjectPtr<UStaticMeshComponent> LastHoverCmp;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Movable Interaction", meta=(AllowPrivateAccess=true))
	double DetectDistance=100000.0;
	
	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Movable Interaction", meta=(AllowPrivateAccess=true))
	float ControlHandleSizeOnScreen = 0.3f;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Movable Interaction", meta=(AllowPrivateAccess=true))
	float RotationSpeed = 0.3f;

	UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Movable Interaction", meta=(AllowPrivateAccess=true))
	float ScaleSpeed = 0.01f;

	UPROPERTY(BlueprintReadOnly, Category="Movable Interaction", meta=(AllowPrivateAccess=true))
	bool bIsDragging;

	UPROPERTY(BlueprintReadOnly, Category="Movable Interaction", meta=(AllowPrivateAccess=true))
	FPlane ConstraintPlane;
	
	ETransformMode eTranformMode = ETransformMode::ETM_Translation;

	FVector StartDragPos;
	FVector LastDragPos;
	FVector StartActorPos;
	FRotator StartActorRotator;
	FVector StartActorScale{1.f, 1.f, 1.f};

	float DraggedAngle;
};

